
#include <iostream>
#include <assert.h>
#include <vector>
#include <unistd.h>
#include "Task.hpp"    //导入的方法文件
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace  std;

#define NAM_OF_PRO 5

// 对命令进行处理
int waitcommand(int fd, bool& quit)
{
   uint32_t command = 0; // 取个32位的类型，用来获取4字节的数据
   ssize_t byte = read(fd,  &command,  sizeof command);
   // 如果父进程没有发送  
   if (byte == 0)  
   {
      quit = true;  // 命令管道开启  //你将他开启了
      return 0;
   }
  // 检测是否是4字节的命令消息1
   assert(byte == sizeof (uint32_t));
   return command;
}

 int main()
 { 

   // 阶段一 ； 创建多个子进程
   // 放pid 与 创建时所在的端口——fd
   vector<pair<pid_t, int>> slots; // slots 位置的意思 
   Taskloading();  // 对方法进行加载

   // 创建多个进程
   for (int i = 0; i < NAM_OF_PRO; i++)
   {
    // 建立管道
    int pipefil[2] = {0};
    int ret = pipe(pipefil);
    assert(ret != -1); // 管道检测

    // 创建子进程
    pid_t fd = fork();
     if (fd == 0)  // 子进程
    {
      // 关闭写端
      close(pipefil[1]);
       while (1)
       {   
         // 处理子进程任务
         //未接收数据，子进程进入阻塞状态
         // 阶段二：为子进程设置任务
         bool quit  = false;   // 管道是否被使用
         int k = waitcommand(pipefil[0], quit);  // 进入等待命令函数
         // cout << "K:" << k << " quit " << quit  << endl;
         if (quit)
            break;  // 目的：当我们开始关闭管道时，read()会读取0字节，这时让子进程退出
         //你看懂了吗，子进程和父进程不共享全局变量的，首先是两者以只读的方式看到同一个tasklist
         //但是后续的父进程进行push_back的时候，发生写实拷贝
         ///能理解吗？ 能了
         //我们现在还能再打印tasklist看看

         tasklist[k]();  // 利用函数容器直接调用，方法函数
         //不能这么说，应该说，子进程非法访问崩溃了，成为僵尸进程了。
       } 
       exit(1);
    }
   
   // 父进程，关闭读端
   close(pipefil[0]);
   // 同时记录子进程，pid数据
   slots.push_back({fd, pipefil[1]});
   }
   
   // 阶段二： 父进程向子进程传递命令信息
   // 要想达到子进程接受命令较合理——负载均衡。
   srand((unsigned)time(0) ^ getpid() * 233333);  // 位运算与相乘2333333，目的是：让数据更随机
   uint32_t command = 0;

   while (true)
   {
   // 玩法1.  手动输入命令
   // cout << "###########################################################\n";
   // cout << "##     0. 退出  1. 查看方法表      2. 输入命令  #############\n";
   // cout << "###########################################################\n";
   // cout <<  "请输入：";
   // cin >> command;

	// //你往管道里面写数据的逻辑在哪里，定位到那里先
   // //子进程正常执行了，你的问题是什么    
   //  if (command ==  1 )
   //  {
   //    print_task();
   //    // continue;
   //  } else if ( command == 2)
   //  {
   //    cout << "Please imput command : ";
   //    cin >> command;
  
   // 玩法2. 随机派发任务
   command = rand() % tasklist.size();


      if (!(command >= 0 && command < tasklist.size()))
      {
         cout << "无效命令" << endl;
         continue;
      }

      size_t n = rand() % slots.size();  // 随机数选择子进程
      ssize_t ret = write(slots[n].second, &command, sizeof command);
      if ( ret != sizeof command)
      {
         cout << " write  fail " << endl;
      }else
      {
         cout << " write success " << "  child pid:[" << slots[n].first << "] " << "执行："
         << command << " " << task_inf[command]<< endl;
      }

   //  }else if (command == 0)
   //  {
   //    cout << "退出成功" << endl;
   //    break;
   //  }
   //  else
   //  {
   //     cout << "无效命令,请重新输入" << endl;
   //  }

    sleep(1);
   }

   // 完成分配后，关闭管道
   for (const auto& e : slots)
    {
        close(e.second);
    }

   // 回收子进程
   for (const auto& e : slots)
   {
       waitpid(e.first, nullptr, 0); // 由于auto只遍历一次，所以不能用轮询回收
   }

    return 0;
 }






